package com.gusto.engine.semsim.measures.impl;

import java.util.List;

import org.apache.log4j.Logger;

import com.gusto.engine.beans.exceptions.PropertyAccessException;
import com.gusto.engine.beans.model.Res;
import com.gusto.engine.semsim.exceptions.SimilarityException;
import com.gusto.engine.semsim.measures.ResourceSimilarity;
import com.gusto.engine.semsim.measures.SetSimilarity;
import com.gusto.engine.semsim.measures.Similarity;
import com.gusto.engine.semsim.measures.ValueSimilarity;
import com.gusto.engine.semsim.measures.types.SemTypes;

/**
 * <p>{@code PropertySimilarity} allows to calculate the similarity between two resources
 * as the similarity between the values of a property.<br/>
 * For a more generic case, and several properties, see {@link ComposedSimilarity}</p>
 * @author amokrane.belloui@gmail.com
 */
public class PropertySimilarity implements ResourceSimilarity {
	
	private Logger log = Logger.getLogger(getClass());
	
	private PropertySimilarityParam param = new PropertySimilarityParam();
	public void setParam(PropertySimilarityParam param) {
		this.param = param;
	}
	
	public String getId() {
		String id = "<" + getClass().getName() + "|";
		id += param.getProperty() + "|";
		id += param.getType() + "|";
		id += param.getSimilarity().getId() + "|";
		id += ">";
		return id;
	}
	
	public Double getSimilarity(Res value1, Res value2) throws SimilarityException, PropertyAccessException {
		SemTypes type = param.getType();
		Similarity similarity = param.getSimilarity();
		Double sim = getSimilarity(value1, value2, param.getProperty(), type, similarity);
		if (sim.equals(Double.NaN)) {
			sim = 0.0;
		}
		log.info("Property similarity '" + param.getProperty() + "' (" + value1  + ", " + value2 + ") = " + (sim));
		return (sim);
	}
	
	private Double getSimilarity(Res value1, Res value2, String property, SemTypes type, Similarity similarity) throws SimilarityException, PropertyAccessException {
		if (type.equals(SemTypes.VALUE)) {
			ValueSimilarity valueSimilarity = (ValueSimilarity)similarity;
			
			Object lp1 = value1.getValueProperty(property);
			Object lp2 = value2.getValueProperty(property);
			
			if (lp1 != null && lp2 != null) {
				double sim = valueSimilarity.getSimilarity(lp1, lp2);
				return sim;
			}
		}
		else if (type.equals(SemTypes.RESOURCE)) {
			ResourceSimilarity resourceSimilarity = (ResourceSimilarity)similarity;
			
			Res rp1 = value1.getResourceProperty(property);
			Res rp2 = value2.getResourceProperty(property);
			
			if (rp1 != null && rp2 != null) {
				double sim = resourceSimilarity.getSimilarity(rp1, rp2);
				return sim;
			}
			
		}
		else if (type.equals(SemTypes.SET)) {
			SetSimilarity setSimilarity = (SetSimilarity)similarity;
			
			if (setSimilarity.getType().equals(SemTypes.RESOURCE)) {
				List<Res> list1 = value1.getResourceSetProperty(property);
				List<Res> list2 = value2.getResourceSetProperty(property);
				return setSimilarity.getSimilarity(list1, list2);
			}
			else if (setSimilarity.getType().equals(SemTypes.VALUE)) {
				List<Object> list1 = value1.getValueSetProperty(property);
				List<Object> list2 = value2.getValueSetProperty(property);
				return setSimilarity.getSimilarity(list1, list2);
			}
		}
		return Double.NaN;
	}
	
}
